Learn Raw React — no JSX, no Flux, no ES6, no Webpack…

So you’ve heard all the fuss about React.js – apparently it is the best thing since XMLHttpRequest. But you’ve spent a couple hours investigating, only to find so many buzzwords that it just feels overwhelming. JSX and flux and ES6 and webpack and react-router and all I want is somebody to just tell me how to use React already!

Luckily for you, that’s exactly what this series will do! Don’t believe me? That’s OK – you will after you’ve built your first React app in about 2 minutes time. Without downloading anything. Just by following this exercise:

Exercise 1 – Write a single-file React.js app

Have you worked with JavaScript, CSS and HTML before? Great! That means you can do this exercise!

The result of this exercise is a single HTML file, which contains your first React app. There are three steps, starting with:

Step 1

Copy this HTML into a new file and save it somewhere:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>I'm in a React app!</title>
  </head>
  <body>
    <div id="react-app"></div>

    <script src="https://cdn.jsdelivr.net/react/0.14.0-rc1/react.js"></script>
    <script src="https://cdn.jsdelivr.net/react/0.14.0-rc1/react-dom.js"></script>
  </body>
</html>

This HTML file does two important things – it creates the div where your rendered content will live (with id react-app), and it loads the two library files where React lives.

With that done, let’s move on to:

Step 2

Type this script into a new <script> tag at the end of your HTML file.

Why type it out instead of copy and paste? Well, typing forces you to process each of the individual commands, drilling them into your head in the process – while copying and pasting just gives you a short feeling of cleverness and a shot of dopamine. And if you just want dopamine, quit reading and play flappy bird or something.
var rootElement =
  React.createElement('div', {}, 
    React.createElement('h1', {}, "Contacts"),
    React.createElement('ul', {},
      React.createElement('li', {},
        React.createElement('h2', {}, "James Nelson"),
        React.createElement('a', {href: 'mailto:james@jamesknelson.com'}, 'james@jamesknelson.com')
      ),
      React.createElement('li', {},
        React.createElement('h2', {}, "Joe Citizen"),
        React.createElement('a', {href: 'mailto:joe@example.com'}, 'joe@example.com')
      )
    )
  )

ReactDOM.render(rootElement, document.getElementById('react-app'))

Phew, that was a bit of work, wasn’t it? But, hopefully all the repetition will have given you an idea of what that createElement method does. If not, maybe step three will help.

Step 3

Open your HTML file in a web browser, and check that the output looks like this:

Got it? In that case, congratulations! You’ve made your first React.js app, without even installing npm. And to celebrate, let’s have a look at how it works.

Introducing React

At it’s most basic, React is a tool for rendering HTML with JavaScript. ReactDOM.render takes a ReactElement object describing what to render, adding the result to the given DOM node. But how do you create ReactElement objects? That’s where React.createElement comes in.

React.createElement takes three parameters, and returns a ReactElement. From the React documentation:

createElement(string/ReactClass type, [object props], [children ...]) -> ReactElement

The type argument lets us specify what type of HTML element to use; it also lets us specify custom elements (which we’ll learn about later). The props argument is a way of specifying which attributes are defined on the HTML element, as you may have guessed from the mailto link in the exercise. Finally, the children arguments are strings or ReactElement objects (or arrays of the same) which will be used for the returned element’s content. By choosing to omit or specify children, you can return a single ReactElement or an entire tree.

Since createElement is just plain JavaScript, you can mix in loops, if statements, and anything else JavaScript allows. You can also easily substitute in data stored in JSON. For example, if you had a list of contacts but didn’t want to render the ones without e-mail addresses, you could do something like this:

var contacts = [
  {key: 1, name: "James Nelson", email: "james@jamesknelson.com"},
  {key: 2, name: "Bob"}
]

var listElements = contacts
  .filter(function(contact) { return contact.email; })
  .map(function(contact) {
    return React.createElement('li', {key: contact.key},
      React.createElement('h2', {}, contact.name),
      React.createElement('a', {href: 'mailto:'+contact.email}, contact.email)
    )
  })

var rootElement =
  React.createElement('div', {}, 
    React.createElement('h1', {}, "Contacts"),

    // If your `children` is an array, you'll need to give each one a unique `key`
    // prop. I'll explain why a little later.
    React.createElement('ul', {}, listElements)
  )

ReactDOM.render(rootElement, document.getElementById('react-app'))

Neat. So React can be used as a very verbose JavaScript-based templating system! But… surely that wouldn’t explain the cult-like following it has received. What gives?

Components

Did you notice the little ReactClass in the type signature of React.createElement? I skipped over it because we hadn’t used it yet, but can you guess what it does?


The answer is … drum roll please: React.createElement isn’t limited to standard HTML. It also lets you create your very own components!

How? With React.createClass:

var ContactItem = React.createClass({
  propTypes: {
    name: React.PropTypes.string.isRequired,
  },

  render: function() {
    return (
      React.createElement('li', {className: 'Contact'},
        React.createElement('h2', {className: 'Contact-name'}, this.props.name)
      )
    )
  },
});

This little snippet defines a new component called ContactItem. Like HTML elements, a ContactItem accepts a list of attributes (called props). Unlike HTML elements, you can define whatever props you need!

You’d use the above component like so:

var element = React.createElement(ContactItem, {name: "James K Nelson"})

And just as you may expect, element would now contain the value returned by your component’s render function.

If you pass a children argument to createElement, it’s value will be available under this.props.children

Let’s test your understanding with another exercise:

Exercise 2 – Refactor your contact list

Refactor your solution to the first exercise using what you’ve learned. In particular:

Use the following data:

var contacts = [
    {key: 1, name: "James K Nelson", email: "james@jamesknelson.com", description: "Front-end Unicorn"},
    {key: 2, name: "Jim", email: "jim@example.com"},
    {key: 3, name: "Joe"},
]

When you’re done, check your work against this fiddle:

propTypes

You may have noticed that my solution to Exercise Two uses two different values for the propTypes object – one with isRequired, and one without. This suffix can be applied to any of React’s available prop types to indicate that the specific prop must be passed to React.createElement.

But wait a minute, you say. What does the propTypes object actually do?

The secret is that in most cases, propTypes doesn’t actually do anything. In fact, we could completely remove it, and our app would still function identically. So why is it there?

propTypes is a debugging mechanism; it lets React check in real time that the props argument passed tocreateElement actually makes sense. If it doesn’t, React will log a warning to the console:

I’ve included propTypes in this guide because it’ll save you a lot of pain in the long run – even if it isn’t strictly necessary. And you can make it even less painful by printing out the cheatsheet PDF you’ll get when you sign up for my newsletter – but I digress! Now that we know how to display some data, let’s learn how to update it.

Displaying new data

So far, our app has only had to take a static set of data, and render it to the DOM once. But what happens when our data changes?

Despite what you may expect from a tool called React, nothing changes. Unlike the automatically-updating views in so many other JavaScript frameworks, React waits for us to manually order a re-render. So how do we do it?

// Render our app to the DOM element with id `react-app`
var rootElement = React.createElement(ApplicationComponent, initialData)
ReactDOM.render(rootElement, document.getElementById('react-app'))

// Actually, there is no re-render. Just render.
var nextRootElement = React.createElement(ApplicationComponent, updatedData)
ReactDOM.render(nextRootElement, document.getElementById('react-app'))

But where our first render call creates an entire new tree of HTML elements under #react-app, our second call only changes the parts which have actually changed. This is where React gets it’s reputation for performance. In fact, if we were to do this:

var rootElement = React.createElement(ApplicationComponent, data)
ReactDOM.render(rootElement, document.getElementById('react-app'))
ReactDOM.render(rootElement, document.getElementById('react-app'))

The second call to render would do absolutely nothing. Nothing – that is – unless you are rendering an array of elements without assigning a unique key prop to each. To understand why this is, you’ll need to know a little about how render works under the hood.

How ReactDOM.render works

The first call to ReactDOM.render is simple – it walks through the passed in ReactElement and creates a corresponding HTML tree under #react-app. But as I mentioned above, the second and subsequent calls don’t modify previously rendered HTML elements unless the corresponding ReactElement objects have changed. Why?

In order to decide what to change, React compares the new ReactElement tree with the previous one. It uses a number of rules to decide what to do:

There’s one catch – when React encounters an array of ReactElements with identical type and props, despite looking identical from the outside it cannot know that they are really identical. This is because elements can have internal state – for example, whether the element currently has user focus. This becomes a problem when React goes to re-render those elements, as it cannot tell one from another – and thus doesn’t know if their order within the array has changed.

This is where the key property from the earlier examples comes in. It lets React distinguish between elements, and keep the DOM aligned with our ReactElement tree.

But enough theory, let’s talk about something practical.

Forms

You now know enough to add a form to your app! That is, as long as you don’t mind that users won’t be able to interact with it yet. But why this limitation?

In React, input elements aren’t actually all that special. They take a value prop, and they’ll display what that value is. And since a component can’t directly change the props which are passed in from the outside world – user input won’t cause any change in the displayed value.

Take a moment to let that sink in. If you type into a form input with a value attribute, nothing changes. This isn’t to say the value can’t change – if you listen to the input events and update the value accordingly, you can change it however you’d like. More about this later, though.

In addition to value, input elements take the props you’d expect them to. With a few minor exceptions, the attributes you can pass to a HTML <input> are also available as props. There are two exceptions worth keeping in mind:

These exceptions are listed on the React cheatsheet you’ll receive after signing up for my newsletter.

Exercise 3: Add a read-only form

Let’s create a new ContactForm component class, with the following propTypes:

propTypes: {
  contact: React.PropTypes.object.isRequired
},

It should render a <form> element containing <input> elements for name and email, a <textarea> for description, and a <button type="submit">. For simplicity, use placeholders instead of labels. And remember – the React textarea component accepts it’s value under props, not children.

Once you’ve built your ContactForm class, add it beneath your contact list with a blank contact passed in for the contact prop. I’ll wait here until you’re done.


Done? Great! Now check how your implementation compares to mine – take note of any differences, but don’t get too hung up on matching my implementation line-for-line. The important thing is that you write something which works.

Making your app beautiful

You haven’t even finished this article, and you’re already on your way to killing salesforce. But nobody is going to buy your product if it looks shit. So let’s add some style.

How should we go about this? Well, since this app is tiny, we could just style it using HTML selectors:

ul {
  background: #ff0000;
}

But this will stop working if our app ever gains another list – so let’s avoid headaches later and assign classes to our elements. To avoid conflicts, we’ll namespace them with their parent component’s class name.

For our ContactItem component, this will look something like this:

render: function() {
  return (
    React.createElement('li', {className: 'ContactItem'},
      React.createElement('h2', {className: 'ContactItem-name'}, this.props.name),
      React.createElement('a', {className: 'ContactItem-email', href: 'mailto:'+this.props.email}, this.props.email),
      React.createElement('div', {className: 'ContactItem-description'}, this.props.description)
    )
  )
},
Note that like the DOM, React uses the className property to assign CSS classes (as class is a reserved word in JavaScript).

But how do we pick class names for our createElement calls which aren’t part of a component render function?

You’ll generally find that React projects organise everything into classes, with a single React.createElement call rendering a top-level element which is directly passed to ReactDOM.render. For this app, let’s use a top-level ContactView with this signature:

propTypes: {
  contacts: React.PropTypes.array.isRequired,
  newContact: React.PropTypes.object.isRequired,
},

Exercise 4 (optional):

If you’d like to style your new app, create the ContactView class as defined above, add className props where relevant, and add a stylesheet to your HTML file.

Need ideas? Here is a fiddle I prepared earlier:

Nobody likes a read-only app

You now know enough to make pretty apps, but how do you learn to make interactive ones?

This article is only the first in a series on Raw React. I aim to release a new article every week, and won’t be stopping until you can use them to make a real app with React. That means an app which:

Update: Part 2: Ridiculously Simple Forms has been released.

In return for your e-mail address, I’ll send you the complete series via e-mail as it is released. And as a bonus you’ll immediately receive 3 print-optimised PDF cheatsheets – on React, ES6 and JavaScript promises.

Read more